﻿/// <summary>
/// 循环利用列表子项
/// Author: LXF
/// </summary>

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;

[RequireComponent(typeof(GridLayoutGroup))]
public class UGUIWrapContent : MonoBehaviour {
    protected void Awake() {
        m_hasInit = false;
        m_realChildObjCnt = 0;
        m_realIndex = -1;
        m_realIndexUp = -1;
        m_selfTrans = transform;
        m_childsAnchoredPos = new Dictionary<Transform, Vector2>();
        m_childsSiblingIndex = new Dictionary<Transform, int>();
        m_childrenRectTransList = new List<RectTransform>();
    }

    IEnumerator InitChildren() {
        yield return 0;
        bool needReDraw = false;
        if (!m_hasInit) {
            FirstTimeInit();
            needReDraw = true;
        }
        else {
            bool needReLocate = false;
            if (m_realChildObjCnt >= m_dataChildCnt) {
                needReDraw = true;
                needReLocate = true;
            }

            if (needReLocate) {
                ResetChildrenPos();
            }
        }
        if (needReDraw) {
            ReDrawChildren();
        }
    }

    private void FirstTimeInit() {
        //获取Grid的宽度;
        m_rectTrans = GetComponent<RectTransform>();

        m_gridLayoutGroup = GetComponent<GridLayoutGroup>();
        m_gridLayoutGroup.enabled = false;

        m_gridLayoutPos = m_rectTrans.anchoredPosition;
        m_gridLayoutSize = m_rectTrans.sizeDelta;


        //注册ScrollRect滚动回调;
        if (null != m_scrollRect)
            m_scrollRect.onValueChanged.AddListener((data) => { ScrollCallback(data); });
        else
            Debug.LogError("null == ScrollRect,请给脚本的ScrollRect赋值");

        m_realChildObjCnt = m_selfTrans.childCount;
        //获取所有child anchoredPosition 以及 SiblingIndex;
        for (int index = 0, cnt = m_selfTrans.childCount; index < cnt; index++) {
            Transform child = m_selfTrans.GetChild(index);
            RectTransform childRectTrans = child.GetComponent<RectTransform>();
            m_childsAnchoredPos.Add(child, childRectTrans.anchoredPosition);
            m_childsSiblingIndex.Add(child, child.GetSiblingIndex());
        }
    }

    private void ResetChildrenPos() {
        m_rectTrans.anchoredPosition = m_gridLayoutPos;
        m_rectTrans.sizeDelta = m_gridLayoutSize;

        m_childrenRectTransList.Clear();

        m_realIndex = -1;
        m_realIndexUp = -1;

        //children重新设置上下顺序;
        foreach (var info in m_childsSiblingIndex) {
            info.Key.SetSiblingIndex(info.Value);
        }

        //children重新设置anchoredPosition;
        for (int index = 0; index < m_selfTrans.childCount; index++) {
            Transform child = m_selfTrans.GetChild(index);

            RectTransform childRectTrans = child.GetComponent<RectTransform>();
            if (m_childsAnchoredPos.ContainsKey(child)) {
                childRectTrans.anchoredPosition = m_childsAnchoredPos[child];
            }
            else {
                Debug.LogError("childsAnchoredPosition no contain " + child.name);
            }
        }
    }

    private void ReDrawChildren() {
        //获取所有child;
        for (int index = 0; index < m_selfTrans.childCount; index++) {
            Transform trans = m_selfTrans.GetChild(index);
            trans.gameObject.SetActive(true);

            m_childrenRectTransList.Add(m_selfTrans.GetChild(index).GetComponent<RectTransform>());

            //初始化前面几个;
            UpdateChildrenCallback(m_childrenRectTransList.Count - 1, m_selfTrans.GetChild(index));
        }

        m_startPos = m_rectTrans.anchoredPosition;

        m_realIndex = m_childrenRectTransList.Count - 1;

        m_hasInit = true;

        //如果需要显示的个数小于设定的个数;
        for (int index = 0; index < m_realChildObjCnt; index++) {
            m_childrenRectTransList[index].gameObject.SetActive(index < m_dataChildCnt);
        }

        if (m_gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount) {
            //如果小了一行，则需要把GridLayout的高度减去一行的高度;
            int row = m_realChildObjCnt - m_dataChildCnt;
            if (row > 0) {
                m_rectTrans.sizeDelta -= new Vector2(0, (m_gridLayoutGroup.cellSize.y + m_gridLayoutGroup.spacing.y) * row);
            }
        }
        else {
            //如果小了一列，则需要把GridLayout的宽度减去一列的宽度;
            int column = m_realChildObjCnt - m_dataChildCnt;
            if (column > 0) {
                m_rectTrans.sizeDelta -= new Vector2((m_gridLayoutGroup.cellSize.x + m_gridLayoutGroup.spacing.x) * column, 0);
            }
        }
    }


    void ScrollCallback(Vector2 data) {
        UpdateChildren();
    }

    void UpdateChildren() {
        if (m_selfTrans.childCount < m_realChildObjCnt) {
            return;
        }

        Vector2 currentPos = m_rectTrans.anchoredPosition;

        if (m_gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount) {
            float offsetY = currentPos.y - m_startPos.y;

            if (offsetY > 0) {
                if (!OnMoveUp(currentPos)) return;
            }
            else {
                //向下拉，下面收缩;
                if (!OnMoveDown(currentPos)) return;
            }
        }
        else {
            float offsetX = currentPos.x - m_startPos.x;

            if (offsetX < 0) {
                //向左拉，向右扩展;
                if (!OnMoveLeft(currentPos)) return;
            }
            else {
                //向右拉，右边收缩;
                if (!OnMoveRight(currentPos)) return;
            }
        }

        m_startPos = currentPos;
    }

    private bool OnMoveUp(Vector2 currentPos) {
        //向上拉，向下扩展;
        if (m_realIndex >= m_dataChildCnt - 1) {
            m_startPos = currentPos;
            return false;
        }

        float scrollRectUp = m_scrollRect.transform.TransformPoint(Vector3.zero).y;

        var topChild = m_childrenRectTransList[0];
        var bottomChild = m_childrenRectTransList[m_childrenRectTransList.Count - 1];

        Vector3 childBottomLeft = new Vector3(topChild.anchoredPosition.x, topChild.anchoredPosition.y - m_gridLayoutGroup.cellSize.y, 0f);
        float childBottom = m_selfTrans.TransformPoint(childBottomLeft).y;

        if (childBottom >= scrollRectUp) {
            //移动到底部//
            topChild.SetAsLastSibling();
            var posY = bottomChild.anchoredPosition.y - m_gridLayoutGroup.cellSize.y - m_gridLayoutGroup.spacing.y;
            topChild.anchoredPosition = new Vector2(topChild.anchoredPosition.x, posY);

            m_realIndex++;

            if (m_realIndex > m_dataChildCnt - 1) {
                topChild.gameObject.SetActive(false);
            }
            else {
                UpdateChildrenCallback(m_realIndex, topChild);
            }


            //GridLayoutGroup 底部加长;
            m_rectTrans.sizeDelta += new Vector2(0, m_gridLayoutGroup.cellSize.y + m_gridLayoutGroup.spacing.y);

            //更新child;
            RetTagChildren();
        }
        return true;
    }

    private bool OnMoveDown(Vector2 currentPos) {
        if (m_realIndex + 1 <= m_childrenRectTransList.Count) {
            m_startPos = currentPos;
            return false;
        }
        RectTransform scrollRectTransform = m_scrollRect.GetComponent<RectTransform>();
        Vector3 scrollRectAnchorBottom = new Vector3(0, -scrollRectTransform.rect.height - m_gridLayoutGroup.spacing.y, 0f);
        float scrollRectBottom = m_scrollRect.transform.TransformPoint(scrollRectAnchorBottom).y;
        var lastChild = m_childrenRectTransList[m_childrenRectTransList.Count - 1];
        Vector2 childUpLeft = lastChild.anchoredPosition + new Vector2(0, m_gridLayoutGroup.cellSize.y);

        float childUp = m_selfTrans.TransformPoint(childUpLeft).y;

        if (childUp < scrollRectBottom) {
            //把底部的一行 移动到顶部
            var childCnt = m_childrenRectTransList.Count;
            var bottomChild = m_childrenRectTransList[childCnt - 1];
            var topChild = m_childrenRectTransList[0];
            bottomChild.SetAsFirstSibling();
            var posY = topChild.anchoredPosition.y + m_gridLayoutGroup.cellSize.y + m_gridLayoutGroup.spacing.y;
            bottomChild.anchoredPosition = new Vector2(bottomChild.anchoredPosition.x, posY);

            bottomChild.gameObject.SetActive(true);

            UpdateChildrenCallback(m_realIndex - childCnt, bottomChild);
            --m_realIndex;
            //GridLayoutGroup 底部缩短;
            m_rectTrans.sizeDelta -= new Vector2(0, m_gridLayoutGroup.cellSize.y + m_gridLayoutGroup.spacing.y);

            //更新child;
            RetTagChildren();
        }
        return true;
    }

    private bool OnMoveLeft(Vector2 currentPos) {
        if (m_realIndex >= m_dataChildCnt - 1) {
            m_startPos = currentPos;
            return false;
        }

        float scrollRectLeft = m_scrollRect.transform.TransformPoint(Vector3.zero).x;
        var leftestChild = m_childrenRectTransList[0];
        var leftestChildPos = leftestChild.anchoredPosition;
        var rightestChild = m_childrenRectTransList[m_childrenRectTransList.Count - 1];
        Vector3 childBottomRight = new Vector3(leftestChildPos.x + m_gridLayoutGroup.cellSize.x, leftestChildPos.y, 0f);
        float childRight = m_selfTrans.TransformPoint(childBottomRight).x;

        if (childRight <= scrollRectLeft) {
            //移动到右边;
            leftestChild.SetAsLastSibling();
            var posX = rightestChild.anchoredPosition.x + m_gridLayoutGroup.cellSize.x + m_gridLayoutGroup.spacing.x;

            leftestChild.anchoredPosition = new Vector2(posX, leftestChildPos.y);

            m_realIndex++;

            if (m_realIndex > m_dataChildCnt - 1) {
                leftestChild.gameObject.SetActive(false);
            }
            else {
                UpdateChildrenCallback(m_realIndex, m_childrenRectTransList[0]);
            }

            //GridLayoutGroup 右侧加长;
            m_rectTrans.sizeDelta += new Vector2(m_gridLayoutGroup.cellSize.x + m_gridLayoutGroup.spacing.x, 0);

            //更新child;
            RetTagChildren();
        }
        return true;
    }

    private bool OnMoveRight(Vector2 currentPos) {
        if (m_realIndex + 1 <= m_childrenRectTransList.Count) {
            m_startPos = currentPos;
            return false;
        }

        var rightestChild = m_childrenRectTransList[m_childrenRectTransList.Count - 1];
        var rightestChildPos = rightestChild.anchoredPosition;
        var leftestChild = m_childrenRectTransList[0];
        RectTransform scrollRectTransform = m_scrollRect.GetComponent<RectTransform>();
        Vector3 scrollRectAnchorRight = new Vector3(scrollRectTransform.rect.width + m_gridLayoutGroup.spacing.x, 0, 0f);
        float scrollRectRight = m_scrollRect.transform.TransformPoint(scrollRectAnchorRight).x;

        Vector2 childUpLeft = rightestChildPos - new Vector2(m_gridLayoutGroup.cellSize.x, 0);

        float childLeft = m_selfTrans.TransformPoint(childUpLeft).x;

        if (childLeft >= scrollRectRight) {
            //把右边的一行 移动到左边;
            rightestChild.SetAsFirstSibling();
            var posX = leftestChild.anchoredPosition.x - m_gridLayoutGroup.cellSize.x - m_gridLayoutGroup.spacing.x;
            rightestChild.anchoredPosition = new Vector2(posX, rightestChildPos.y);

            rightestChild.gameObject.SetActive(true);

            UpdateChildrenCallback(m_realIndex - m_childrenRectTransList.Count, rightestChild);
            --m_realIndex;
            //GridLayoutGroup 右侧缩短;
            m_rectTrans.sizeDelta -= new Vector2(m_gridLayoutGroup.cellSize.x + m_gridLayoutGroup.spacing.x, 0);

            //更新child;
            RetTagChildren();
        }
        return true;
    }

    private void RetTagChildren() {
        for (int index = 0, cnt = m_childrenRectTransList.Count; index < cnt; ++index) {
            var child = m_selfTrans.GetChild(index);
            m_childrenRectTransList[index] = child.GetComponent<RectTransform>();
        }
    }

    void UpdateChildrenCallback(int index, Transform trans) {
        if (updateChildrenCallback != null) {
            updateChildrenCallback(index, trans);
        }
    }


    /// <summary>
    /// 设置总的个数;
    /// </summary>
    /// <param name="count"></param>
    public void SetAmount(int count) {
        m_dataChildCnt = count;

        StartCoroutine(InitChildren());
    }

    /// <summary>
    /// 是否初始化过
    /// </summary>
    private bool m_hasInit = false;

    /// <summary>
    /// 实际的子项Obj数量
    /// </summary>
    private int m_realChildObjCnt;
    /// <summary>
    /// 数据子项数量
    /// </summary>
    private int m_dataChildCnt;

    private RectTransform m_rectTrans;
    private Transform m_selfTrans;
    private GridLayoutGroup m_gridLayoutGroup;

    private List<RectTransform> m_childrenRectTransList;
    private Vector2 m_startPos;

    private int m_realIndex;
    private int m_realIndexUp;

    private Vector2 m_gridLayoutSize;
    private Dictionary<Transform, Vector2> m_childsAnchoredPos;
    private Vector2 m_gridLayoutPos;
    private Dictionary<Transform, int> m_childsSiblingIndex;

    [SerializeField]
    private ScrollRect m_scrollRect;

    public delegate void UpdateChildrenCallbackDelegate(int index, Transform trans);
    public UpdateChildrenCallbackDelegate updateChildrenCallback = null;
}
